﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using Microsoft.ServiceModel.DomainServices.Tools;
    using System;
    using System.Collections.Generic;
    using System.Data.Metadata.Edm;

    internal abstract class LinqToEntitiesContextBase : BusinessLogicContext
    {
        private Dictionary<ComplexType, Type> _complexTypes;
        private HashSet<Type> _visitedComplexTypes;

        public LinqToEntitiesContextBase(Type contextType) : base(contextType, contextType.Name)
        {
            this._visitedComplexTypes = new HashSet<Type>();
            this.PopulateComplexTypesInObjectContext();
        }

        protected override bool CanGeneratePropertyOfType(Type type)
        {
            return (base.CanGeneratePropertyOfType(type) || this.ComplexTypes.ContainsValue(type));
        }

        protected override IEnumerable<BusinessLogicEntity> CreateEntities()
        {
            List<BusinessLogicEntity> list = new List<BusinessLogicEntity>();
            foreach (KeyValuePair<EntityType, Type> pair in this.GetEntityTypesInContext())
            {
                list.Add(new LinqToEntitiesEntity(this, pair.Key, pair.Value));
            }
            return list;
        }

        protected override bool GenerateAdditionalMetadataClasses(CodeGenContext codeGenContext, string optionalSuffix, BusinessLogicEntity entity)
        {
            LinqToEntitiesEntity entity2 = (LinqToEntitiesEntity) entity;
            return this.GenerateMetadataClassesForComplexTypes(codeGenContext, optionalSuffix, entity2.EntityType.Properties);
        }

        private bool GenerateMetadataClassesForComplexTypes(CodeGenContext codeGenContext, string optionalSuffix, IEnumerable<EdmProperty> properties)
        {
            bool flag = false;
            foreach (EdmProperty property in properties)
            {
                EdmType edmType = property.TypeUsage.EdmType;
                if (edmType.BuiltInTypeKind == BuiltInTypeKind.ComplexType)
                {
                    Type type2;
                    ComplexType key = (ComplexType) edmType;
                    if (this.ComplexTypes.TryGetValue(key, out type2) && !this._visitedComplexTypes.Contains(type2))
                    {
                        flag |= base.GenerateMetadataClass(codeGenContext, optionalSuffix, type2);
                        this._visitedComplexTypes.Add(type2);
                        flag |= this.GenerateMetadataClassesForComplexTypes(codeGenContext, optionalSuffix, key.Properties);
                    }
                }
            }
            return flag;
        }

        private Dictionary<EntityType, Type> GetEntityTypesInContext()
        {
            Dictionary<EntityType, Type> dictionary = new Dictionary<EntityType, Type>();
            ObjectItemCollection itemCollection = this.MetadataWorkspace.GetItemCollection(DataSpace.OSpace) as ObjectItemCollection;
            foreach (EntityType type in itemCollection.GetItems<EntityType>())
            {
                StructuralType type3;
                Type clrType = itemCollection.GetClrType(type);
                if (!DbContextUtilities.CompareWithSystemType(clrType, "System.Data.Entity.Infrastructure.EdmMetadata") && this.MetadataWorkspace.TryGetEdmSpaceType(type, out type3))
                {
                    dictionary[(EntityType) type3] = clrType;
                }
            }
            return dictionary;
        }

        private void PopulateComplexTypesInObjectContext()
        {
            ObjectItemCollection itemCollection = this.MetadataWorkspace.GetItemCollection(DataSpace.OSpace) as ObjectItemCollection;
            foreach (ComplexType type in itemCollection.GetItems<ComplexType>())
            {
                StructuralType type3;
                Type clrType = itemCollection.GetClrType(type);
                if (this.MetadataWorkspace.TryGetEdmSpaceType(type, out type3))
                {
                    this.ComplexTypes[(ComplexType) type3] = clrType;
                }
            }
        }

        internal Dictionary<ComplexType, Type> ComplexTypes
        {
            get
            {
                if (this._complexTypes == null)
                {
                    this._complexTypes = new Dictionary<ComplexType, Type>();
                }
                return this._complexTypes;
            }
        }

        public override string DataAccessLayerName
        {
            get
            {
                return Resources.BusinessLogicClass_EntityFramework;
            }
        }

        public abstract System.Data.Metadata.Edm.MetadataWorkspace MetadataWorkspace { get; }
    }
}

